Description
给出一棵n个点、以1为根的有根树,点有点权。要求支持如下两种操作:
M x y:将点x的点权改为y;
Q x:求以x为根的子树的最大连通子块和。
其中,一棵子树的最大连通子块和指的是:该子树所有子连通块的点权和中的最大值
(本题中子连通块包括空连通块,点权和为0)。
Input
第一行两个整数n、m,表示树的点数以及操作的数目。
第二行n个整数,第i个整数w_i表示第i个点的点权。
接下来的n-1行,每行两个整数x、y,表示x和y之间有一条边相连。
接下来的m行,每行输入一个操作,含义如题目所述。保证操作为M x y或Q x之一。
1≤n,m≤200000 ,任意时刻 |w_i|≤10^9 。
Output
对于每个Q操作输出一行一个整数,表示询问子树的最大连通子块和。
Sample Input
5 4
3 -2 0 3 -1
1 2
1 3
4 2
2 5
Q 1
M 4 1
Q 1
Q 2
Sample Output
4
3
1
Solution
对于没有修改的版本,一个DP就可以解决
$f[x] = v[x] + \sum max\{0,\ f[u]\}$
对于带修改的版本,使用动态DP
定义以下状态:
$F[x]$表示以$x$为根的联通块的答案
$H[x]$表示$x$子树中答案$max$
$LH[x]$表示$x$轻儿子的答案$max$
$LF[x]$表示$\sum F[u]$
动态DP上,重链的转移(将重链表示成序列$v_1, v_2…v_n$, 按深度从小到大排序,$v_n$一定没有子节点)
对于链上的DP,构建矩阵转移:(定义加法为取$max$,乘法为加法)
化简一下转移矩阵的相乘:
从转移矩阵中提取答案,事实上就是用向量$[0,0,0]$去乘这一块的转移矩阵,也就是$f=max(a,d),h=max(b,c)$
于是对于一个链,用线段树记录一下一个区间的转移矩阵,再用链底的来乘一下就好了
对于子树的DP,直接线段树加和/取max即可
写的时候注意一下链上线段树的乘法要用右边乘左边(也就是树上下面乘上面)
代码:
1 |
|